#include "stdafx.h"
#include "MyHsmMessageHandler.h"
#include "MyPayload.h"
#include "TypeIds.h"
#include "DefaultConfig.h"

namespace CO { namespace MyGroupNamespace { namespace MyPackageNamespace {

MyHsmMessageHandler::MyHsmMessageHandler(SpiFoundation::RoomFW::ActiveObject* parent) :
	//
	// Initialize Base class.
	//
	SpiFoundation::RoomFW::HsmMessageHandler(parent, reinterpret_cast<QSTATE>(&MyHsmMessageHandler::Initial)),
	//
	// TODO:  Initialize attributes.
	//
	myConfigValue_(0)	// TODO:  Initialize attributes to default!
{
}

bool MyHsmMessageHandler::initialize(SpiFoundation::Configuration::ConfigKey& configRoot)
{
	//
	// TODO:  Initialize attributes with configuration settings.  Get key and value
	//		  will create if they don't exist, so be sure everyone uses the same defines
	//		  to avoid spelling errors!
	//
	configRoot.getValue_T(CFG_VAL_PATH_MyIntValue, myConfigValue_);
	return true;
}

void MyHsmMessageHandler::Initial(MyHsmMessageHandler* me, QEvent const* /*evt*/)
{
	//
	// TODO:  Perform initial transition.
	//
	Q_TRAN(reinterpret_cast<QSTATE>(&MyHsmMessageHandler::StateC));
}

QSTATE MyHsmMessageHandler::StateA(MyHsmMessageHandler* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&QHsm::top); // Parent of top-level states.

	//
	// Catch all exceptions here.  Any that escape will result in the thread exiting.
	//
	try
	{
		switch (evt->sig)
		{
		case Q_ENTRY_SIG:
			//
			// TODO:  Perform state entry actions.
			//
			break;

		case Q_EXIT_SIG:
			//
			// TODO:  Perform state exit actions.
			//
			break;

		case Q_USER_SIG:
			{
				// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
				SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
				switch (message->portIndex().port())
				{
				case MyActiveInterface::PORT_SYSTEM:
					{
						//
						// TODO:  Handle system messages.
						//
						switch (message->messageID())
						{
						case SystemManagerProtocol::I_AM_READY:
							{
								//
								// TODO:  Begin collaborative initialization.
								//
								me->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
							}
							break;
						//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
						//	{
						//		Protocol::ConfigKeyPayloadSP payload =
						//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
						//		ASSERT(0 != payload);
						//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
						//		//
						//		// TODO:  Apply updated configuration settings.
						//		//
						//	}
						//	break;
						}
					}
					break;
				case MyActiveInterface::PORT_MY_PORT_1:
					{
						//
						// TODO:  Handle each message message for this port.
						//
						switch (message->messageID())
						{
						case MyProtocol::IN_MESSAGE_1:
							{
								//
								// TODO:  Handle the message.  See StateB and StateC for state transition examples.
								//
								MyPayloadSP msgPayload = ::boost::dynamic_pointer_cast<MyPayload, SpiFoundation::RoomFW::IPayload>(message->releasePayload());
								if (0 != msgPayload)
								{
									me->sendMessage(message->portIndex(),
													MyProtocol::OUT_MESSAGE_1,
													SpiFoundation::RoomFW::IPayload::ReleaseOwnership(msgPayload));
								}
								retVal = 0; // Indicates that message was handled.
							}
							break;
						}
					}
					break;
				case MyActiveInterface::PORT_TIMER: // Handle timer messages.
					{
						SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
						ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
						//
						// TODO:  Handle timer id.
						//
					}
					break;
				default:
					ASSERT(FALSE); // No more ports!
				}
			}
		}
	}
	//
	// TODO: Catch specific errors and handle them correctly.
	//
	catch (SpiFoundation::ErrorHandling::IError& e)
	{
		e.setSourceObjectName(me->getObjectName());
		G_LOG_0_ERROR(e.what());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	catch (std::exception& e)
	{
		G_LOG_2_ERROR("%s: %s", me->getObjectName(), e.what());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	catch (...) // You must enable SEH exceptions to catch hardware (e.g. memory access) errors.
	{
		G_LOG_1_ERROR("%s: Unhandled Exception", me->getObjectName());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	return retVal;
}

QSTATE MyHsmMessageHandler::StateB(MyHsmMessageHandler* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&MyHsmMessageHandler::StateA); // Parent State.

	//
	// Catch all exceptions here.  Any that escape will result in the thread exiting.
	//
	try
	{
		switch (evt->sig)
		{
		case Q_ENTRY_SIG:
			//
			// TODO:  Perform state entry actions.
			//
			if (me->getParent()->isRunning())
			{
				me->sendMessage(MyActiveInterface::PORT_MY_PORT_1, MyProtocol::OUT_MESSAGE_2);
			}
			break;

		case Q_EXIT_SIG:
			//
			// TODO:  Perform state exit actions.
			//
			break;

		case Q_USER_SIG:
			{
				// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
				SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
				switch (message->portIndex().port())
				{
				case MyActiveInterface::PORT_SYSTEM:
					{
						//
						// TODO:  Handle system messages.
						//
						switch (message->messageID())
						{
						case SystemManagerProtocol::I_AM_READY:
							{
								//
								// TODO:  Begin collaborative initialization.
								//
								me->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
							}
							break;
						//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
						//	{
						//		Protocol::ConfigKeyPayloadSP payload =
						//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
						//		ASSERT(0 != payload);
						//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
						//		//
						//		// TODO:  Apply updated configuration settings.
						//		//
						//	}
						//	break;
						}
					}
					break;
				case MyActiveInterface::PORT_MY_PORT_1:
					{
						//
						// TODO:  Handle each message message for this port.
						//
						switch (message->messageID())
						{
						case MyProtocol::IN_MESSAGE_1:
						case MyProtocol::IN_MESSAGE_2:
							break;	// Handled by parent state.
						case MyProtocol::IN_MESSAGE_3:
							{
								//
								// TODO:  Handle the message.
								//
								Q_TRAN(reinterpret_cast<QSTATE>(&MyHsmMessageHandler::StateC)); // State Transition.
								retVal = 0; // Indicates that message was handled.
							}
							break;
						}
					}
					break;
				case MyActiveInterface::PORT_TIMER: // Handle timer messages.
					{
						SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
						ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
						//
						// TODO:  Handle timer id.
						//
					}
					break;
				default:
					ASSERT(FALSE); // No more ports!
				}
			}
		}
	}
	//
	// TODO: Catch specific errors and handle them correctly.
	//
	catch (SpiFoundation::ErrorHandling::IError& e)
	{
		e.setSourceObjectName(me->getObjectName());
		G_LOG_0_ERROR(e.what());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	catch (std::exception& e)
	{
		G_LOG_2_ERROR("%s: %s", me->getObjectName(), e.what());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	catch (...) // You must enable SEH exceptions to catch hardware (e.g. memory access) errors.
	{
		G_LOG_1_ERROR("%s: Unhandled Exception", me->getObjectName());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	return retVal;
}

QSTATE MyHsmMessageHandler::StateC(MyHsmMessageHandler* me, QEvent const *evt)
{
	//
	// TODO:  Initialize retVal to parent state.  Set retVal to 0 if you handle the message.
	//
	QSTATE retVal = reinterpret_cast<QSTATE>(&MyHsmMessageHandler::StateA); // Parent State.

	//
	// Catch all exceptions here.  Any that escape will result in the thread exiting.
	//
	try
	{
		switch (evt->sig)
		{
		case Q_ENTRY_SIG:
			//
			// TODO:  Perform state entry actions.
			//
			if (me->getParent()->isRunning())
			{
				me->sendMessage(MyActiveInterface::PORT_MY_PORT_1, MyProtocol::OUT_MESSAGE_3);
			}
			break;

		case Q_EXIT_SIG:
			//
			// TODO:  Perform state exit actions.
			//
			break;

		case Q_USER_SIG:
			{
				// Get the room message.  Base class ensures that's what a Q_USER_SIG is.
				SpiFoundation::RoomFW::RoomMessage* message = static_cast<SpiFoundation::RoomFW::RoomMessage*>(const_cast<QEvent*>(evt));
				switch (message->portIndex().port())
				{
				case MyActiveInterface::PORT_SYSTEM:
					{
						//
						// TODO:  Handle system messages.
						//
						switch (message->messageID())
						{
						case SystemManagerProtocol::I_AM_READY:
							{
								//
								// TODO:  Begin collaborative initialization.
								//
								me->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
							}
							break;
						//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
						//	{
						//		Protocol::ConfigKeyPayloadSP payload =
						//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
						//		ASSERT(0 != payload);
						//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
						//		//
						//		// TODO:  Apply updated configuration settings.
						//		//
						//	}
						//	break;
						}
					}
					break;
				case MyActiveInterface::PORT_MY_PORT_1:
					{
						//
						// TODO:  Handle each message message for this port.
						//
						switch (message->messageID())
						{
						case MyProtocol::IN_MESSAGE_1:
						case MyProtocol::IN_MESSAGE_3:
							break;	// Handled by parent state.
						case MyProtocol::IN_MESSAGE_2:
							{
								//
								// TODO:  Handle the message.
								//
								Q_TRAN(reinterpret_cast<QSTATE>(&MyHsmMessageHandler::StateB)); // State Transition.
								retVal = 0; // Indicates that message was handled.
							}
							break;
						}
					}
					break;
				case MyActiveInterface::PORT_TIMER: // Handle timer messages.
					{
						SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
						ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
						//
						// TODO:  Handle timer id.
						//
					}
					break;
				default:
					ASSERT(FALSE); // No more ports!
				}
			}
		}
	}
	//
	// TODO: Catch specific errors and handle them correctly.
	//
	catch (SpiFoundation::ErrorHandling::IError& e)
	{
		e.setSourceObjectName(me->getObjectName());
		G_LOG_0_ERROR(e.what());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	catch (std::exception& e)
	{
		G_LOG_2_ERROR("%s: %s", me->getObjectName(), e.what());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	catch (...) // You must enable SEH exceptions to catch hardware (e.g. memory access) errors.
	{
		G_LOG_1_ERROR("%s: Unhandled Exception", me->getObjectName());
#pragma message(__HERE__"TODO: Remove the following two lines and actually handle the error!  (the throw will exit the thread)")
		ASSERT(false);
		throw;
	}
	return retVal;
}

}}} // End namespace
